﻿using Network.Tcp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Unicode;
using System.Threading.Tasks;

namespace Network.StepProtocol;

public class StepProtocol : ITcpSubscriber
{
    public StepProtocol(TcpBase tcp, IStepPackageFactory stepPackageFactory)
    {
        Tcp = tcp;
        StepPackageFactory = stepPackageFactory;
        Tcp.SubscribeTcp(this);
    }
    public void SubscribeStep(IStepSubscriber stepSubscriber)
    {
        StepSubscriber = stepSubscriber;
    }
    public void SetTimeOut(int milliSeconds)
    {
        Tcp.SetTimeOut(milliSeconds);
    }
    public void SetTimer(int milliSeconds)
    {
        (Tcp as TcpClientBase as Tcp.ITimer)?.SetTimer(milliSeconds);
    }
    public bool Connect(IPEndPoint ipEndPoint)
    {
        if (Tcp is not TcpClientBase tcpClient)
        {
            return false;
        }
        return tcpClient.Connect(ipEndPoint);
    }
    public bool AddConnectTarget(IPEndPoint ipEndPoint)
    {
        if (Tcp is not TcpClientBase tcpClient)
        {
            return false;
        }
        return tcpClient.AddConnectTarget(ipEndPoint);
    }
    public void SetBindAddress(IPEndPoint bindIPEndPoint)
    {
        (Tcp as TcpServerBase)?.SetBindAddress(bindIPEndPoint);
    }
    public bool Init()
    {
        return Tcp.Init();
    }
    public bool Start()
    {
        return Tcp.Start();
    }
    public void Stop()
    {
        Tcp.Stop();
    }
    public void Join()
    {
        Tcp.Join();
    }

    public void DisConnect(long sessionID)
    {
        Tcp.DisConnect(sessionID);
    }
    public bool Send(StepPackageBase stepPackage)
    {
        TcpEvent tcpEvent = new TcpEvent();
        tcpEvent.SessionID = stepPackage.SessionID;
        tcpEvent.IPAddress = stepPackage.IPAddress;
        StringBuilder stringBuilder = new StringBuilder();
        stepPackage.MakePackage(stringBuilder);
        tcpEvent.Buff = Encoding.UTF8.GetBytes(stringBuilder.ToString());
        tcpEvent.ReadIndex = 0;
        tcpEvent.Length = tcpEvent.Buff.Length;
        return Tcp.Send(tcpEvent);
    }

    public void OnConnected(ConnectData connectData)
    {
        Console.WriteLine($"StepProtocol: OnConnected sessionID:{connectData.SessionID}, RemoteEndPoint:{connectData.IPEndPoint}");
        SessionPackageReaders.Add(connectData.SessionID, new StepPackageReader(StepPackageFactory, connectData.SessionID, connectData.IPEndPoint));
        StepSubscriber?.OnStepConnected(connectData);
    }
    public void OnDisConnected(ConnectData connectData)
    {
        Console.WriteLine($"StepProtocol: OnDisConnected sessionID:{connectData.SessionID}, RemoteEndPoint:{connectData.IPEndPoint}");
        SessionPackageReaders.Remove(connectData.SessionID);
        StepSubscriber?.OnStepDisConnected(connectData);
    }
    public void OnRecv(TcpEvent tcpEvent)
    {
        var reader = SessionPackageReaders[tcpEvent.SessionID];
        if (reader == null)
        {
            Console.WriteLine($"Cannot Find StepPackageReader for SessionID:{tcpEvent.SessionID}");
            Tcp.DisConnect(tcpEvent.SessionID);
            return;
        }
        if (!reader.AppendMessage(tcpEvent))
        {
            Tcp.DisConnect(tcpEvent.SessionID);
        }
        while(true)
        {
            if (!reader.ParsePackage(out StepPackageBase? stepPackage))
            {
                Tcp?.DisConnect(tcpEvent.SessionID);
                break;
            }
            else if (stepPackage == null)
            {
                break;
            }
            else
            {
                StepSubscriber?.OnStepMessage(stepPackage);
            }
        }
    }

    protected TcpBase Tcp;
    private IStepPackageFactory StepPackageFactory;
    protected IStepSubscriber? StepSubscriber;
    protected Dictionary<long, StepPackageReader> SessionPackageReaders = new Dictionary<long, StepPackageReader>();
}
